package icg;

import ast.type.OpType;

public class Quadruple {

	private OpType opCode;
	private ElementQ op1, op2, res;
	private EQLabel label;
	private String str;

	private String hasPending() {
		EQLabel l = EQLabel.pending();
		EQLabel.useLabel(null);
		if (l == null || l == EQLabel.FALL)
			return "";
		this.label = l;
		return l.toString() + ": ";
	}

	private Quadruple(OpType opCode, ElementQ res, ElementQ op1, ElementQ op2) {
		super();
		this.opCode = opCode;
		this.res = res;
		this.op1 = op1;
		this.op2 = op2;
		this.str = hasPending();
	}

	static public Quadruple binary(OpType opCode, ElementQ res, ElementQ op1,
			ElementQ op2) {
		Quadruple q = new Quadruple(opCode, res, op1, op2);
		q.str += res + " = " + op1 + " " + opCode + " " + op2;
		return q;
	}

	static public Quadruple negative(ElementQ res, ElementQ op1) {
		Quadruple q = new Quadruple(OpType.NEGATIVE, res, op1, null);
		q.str += res + "= - " + op1;
		return q;
	}

	static public Quadruple branch(OpType opCode, ElementQ res, ElementQ op1,
			ElementQ op2) {
		Quadruple q = new Quadruple(opCode, res, op1, op2);
		q.str += "if " + op1 + " " + opCode + " " + op2 + " goto " + res;
		return q;
	}

	static public Quadruple jump(ElementQ res) {
		Quadruple q = new Quadruple(OpType.GOTO, res, null, null);
		q.str += "goto " + res;
		return q;
	}

	static public Quadruple copy(ElementQ res, ElementQ op1) {
		Quadruple q = new Quadruple(OpType.COPY, res, op1, null);
		q.str += res + " = " + op1;
		return q;
	}

	static public Quadruple funcCall(ElementQ res, ElementQ function,
			ElementQ nArgs) {
		Quadruple q = new Quadruple(OpType.FUNC, res, function, nArgs);
		q.str += res + " = call " + function + ", " + nArgs;
		return q;
	}

	static public Quadruple procCall(ElementQ procedure, ElementQ nArgs) {
		Quadruple q = new Quadruple(OpType.FUNC, null, procedure, nArgs);
		q.str += "call i" + procedure + ", " + nArgs;
		return q;
	}

	static public Quadruple param(ElementQ param) {
		Quadruple q = new Quadruple(OpType.PARAM, param, null, null);
		q.str += "param " + param;
		return q;
	}

	public static Quadruple nop() {
		Quadruple q = new Quadruple(OpType.NOP, null, null, null);
		q.str += "nop";
		return q;
	}

	public static Quadruple retorno() {
		Quadruple q = new Quadruple(OpType.RETURN, null, null, null);
		q.str += "return";
		return q;
	}

	public static Quadruple retorno(ElementQ addr) {
		Quadruple q = new Quadruple(OpType.RETURN, addr, null, null);
		q.str += "return " + addr;
		return q;
	}

	public static Quadruple read(ElementQ addr) {
		Quadruple q = new Quadruple(OpType.READ, addr, null, null);
		q.str += "read " + addr;
		return q;
	}

	public static Quadruple write(ElementQ addr) {
		Quadruple q = new Quadruple(OpType.WRITE, addr, null, null);
		q.str += "WRITE " + addr;
		return q;
	}

	public ElementQ getOp1() {
		return op1;
	}

	public void setOp1(ElementQ op1) {
		this.op1 = op1;
	}

	public ElementQ getOp2() {
		return op2;
	}

	public void setOp2(ElementQ op2) {
		this.op2 = op2;
	}

	public ElementQ getRes() {
		return res;
	}

	public void setRes(ElementQ res) {
		this.res = res;
	}

	@Override
	public String toString() {

		return this.str;
	}

	public OpType getOpCode() {
		return opCode;
	}

	public void setOpCode(OpType opCode) {
		this.opCode = opCode;
	}

	public EQLabel getLabel() {
		return label;
	}

	public void setLabel(EQLabel label) {
		this.label = label;
	}
}
